/*!
* @file Vector2d.cpp
* @brief 二维矢量（点）
* @date 2024/9/11
*/
#pragma once

#include "Vector2D.h"

using namespace data;

template<class float_type>
bool Vector2<float_type>::operator==(const Vector2<float_type>& v) const
{
    return (std::fabs(x - v.x) <= traits_type::epsilon())
        && (std::fabs(y - v.y) <= traits_type::epsilon());
}

template<class float_type>
bool Vector2<float_type>::operator!=(const Vector2<float_type>& v) const
{
    return !((*this) == v);
}

template<class float_type>
Vector2<float_type> Vector2<float_type>::operator+() const
{
    return Vector2<float_type>(x, y);
}

template<class float_type>
Vector2<float_type> Vector2<float_type>::operator+(const Vector2<float_type>& v) const
{
    return Vector2<float_type>(x + v.x, y + v.y);
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::operator+=(const Vector2<float_type>& v)
{
    x += v.x;
    y += v.y;
    return *this;
}

template<class float_type>
Vector2<float_type> Vector2<float_type>::operator-() const
{
    return Vector2<float_type>(-x, -y);
}

template<class float_type>
Vector2<float_type> Vector2<float_type>::operator-(const Vector2<float_type>& v) const
{
    return Vector2<float_type>(x - v.x, y - v.y);
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::operator-=(const Vector2<float_type>& v)
{
    x -= v.x;
    y -= v.y;
    return *this;
}

template<class float_type>
Vector2<float_type> Vector2<float_type>::operator*(float_type c) const
{
    return Vector2<float_type>(c * x, c * y);
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::operator*=(float_type c)
{
    x *= c;
    y *= c;
    return *this;
}

template<class float_type>
float_type Vector2<float_type>::operator*(const Vector2<float_type>& v) const
{
    return x * v.x + y * v.y;
}

template<class float_type>
Vector2<float_type> Vector2<float_type>::operator/(float_type c) const
{
    return Vector2<float_type>(x / c, y / c);
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::operator/=(float_type c)
{
    x /= c;
    y /= c;
    return *this;
}

template<class float_type>
float_type Vector2<float_type>::Length() const
{
    return sqrt(x * x + y * y);
}

template<class float_type>
float_type Vector2<float_type>::Angle() const
{
    return atan2(y, x);
}

template<class float_type>
float_type Vector2<float_type>::Sqr() const
{
    return x * x + y * y;
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::Set(float_type x, float_type y)
{
    this->x = x;
    this->y = y;
    return *this;
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::Negate()
{
    x = -x;
    y = -y;
    return *this;
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::Scale(float_type factor)
{
    x *= factor;
    y *= factor;
    return *this;
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::Rotate(float_type angle)
{
    float_type tmp_x = x;
    x = x * cos(angle) - y * sin(angle);
    y = tmp_x * sin(angle) + y * cos(angle);
    return *this;
}

template<class float_type>
Vector2<float_type>& Vector2<float_type>::Normalize()
{
    float_type length = Length();
    if (length > 0.0)
    {
        x /= length;
        y /= length;
    }
    return *this;
}

template<class float_type>
bool Vector2<float_type>::IsZero() const
{
    return x == 0.0 && y == 0.0;
}

template<class float_type>
float_type Vector2<float_type>::Distance(const Vector2<float_type>& v) const
{
    float_type dx = (x - v.x);
    float_type dy = (y - v.y);
    return sqrt(dx * dx + dy * dy);
}

template<class float_type>
bool Vector2<float_type>::IsEqual(const Vector2<float_type>& v, float_type tol) const
{
    return Distance(v) <= tol;
}

template<class float_type>
float_type Vector2<float_type>::GetAngle(const Vector2<float_type>& vec) const
{
    float_type len1 = Length();
    float_type len2 = vec.Length();
    if (len1 <= traits_type::epsilon() || len2 <= traits_type::epsilon())
    {
        return traits_type::quiet_NaN();  // division by zero
    }

    float_type dot = (*this) * vec;
    dot /= len1;
    dot /= len2;

    if (dot <= -1.0)
    {
        return (float_type)D_PI;
    }
    if (dot >= 1.0)
    {
        return 0.0;
    }
    return float_type(acos(dot));
}

//导出
namespace Base
{
    template class DATA_API Vector2<float>;
    template class DATA_API Vector2<double>;
}
